package org.breathe.dynamic.thread.pool.core.monitor;

import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.breathe.dynamic.thread.pool.core.convert.MetricsConverter;
import org.breathe.dynamic.thread.pool.core.event.CollectEvent;
import org.breathe.dynamic.thread.pool.core.executor.ThreadPoolExecutorRegistry;
import org.breathe.dynamic.thread.pool.core.handler.CollectorHandler;
import org.breathe.dynamic.thread.pool.core.notify.alarm.AlarmManager;
import org.breathe.dynamic.thread.pool.core.thread.BreatheDtpExecutor;
import org.breathe.dynamic.thread.pool.core.thread.NamedThreadFactory;
import org.breathe.thread.pool.common.entity.BreatheDtpProperties;
import org.breathe.thread.pool.common.entity.ThreadPoolStats;
import org.breathe.thread.pool.common.enums.NotifyTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.event.ApplicationEventMulticaster;

import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 动态线程池监控类
 * @author: breathe
 * @createTime: 2025-04-14
 */
@Slf4j
public class BreatheDtpMonitor implements ApplicationRunner {
    private static final List<NotifyTypeEnum> ALARM_TYPES = Lists.newArrayList(NotifyTypeEnum.LIVENESS, NotifyTypeEnum.CAPACITY);

    private static final ScheduledExecutorService MONITOR_EXECUTOR = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("breathe-dtp-monitor", true));

    @Autowired
    private BreatheDtpProperties breatheDtpProperties;

    @Autowired
    private ApplicationEventMulticaster applicationEventMulticaster;

    @Override
    public void run(ApplicationArguments args) {
        MONITOR_EXECUTOR.scheduleWithFixedDelay(this::run, 5, breatheDtpProperties.getMonitorInterval(), TimeUnit.SECONDS);
    }

    private void run() {
        List<String> names = ThreadPoolExecutorRegistry.listAllBreatheDtpNames();
        if (CollUtil.isEmpty(names)) {
            return ;
        }
        names.forEach(name -> {
            BreatheDtpExecutor executor = ThreadPoolExecutorRegistry.get(name);
            AlarmManager.triggerAlarm(() -> AlarmManager.doAlarm(executor, ALARM_TYPES));
            ThreadPoolStats threadPoolStats = MetricsConverter.convert(executor);
            doCollect(threadPoolStats);
        });
        publishEvent();
    }
    private void doCollect(ThreadPoolStats threadPoolStats) {
        if (!breatheDtpProperties.isEnabledCollect()) {
            return ;
        }
        try {
            CollectorHandler.getInstance().collect(threadPoolStats, breatheDtpProperties.getCollectorType());
        } catch (Exception ex) {
            log.error("breathe dynamic thread pool monitor, metrics collect error ...", ex);
        }
    }

    private void publishEvent() {
        CollectEvent event = new CollectEvent(this, breatheDtpProperties);
        applicationEventMulticaster.multicastEvent(event);
    }
}